package org.sosie2.service.audit;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.InvalidPropertiesFormatException;
import java.util.Properties;
import java.util.Vector;

import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import org.apache.axis.message.SOAPEnvelope;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.opensaml.SAMLException;
import org.sosie2.service.framework.AbstractService;
import org.sosie2.service.framework.SAMLAnnotation;
import org.sosie2.service.framework.Utils;


/**
 * 
 * Is a web service with the purpose of forwarding email alerts when a SOAP 
 * message satisfies a certain condition. 
 * This service firstly configures itself and parses the configuration file,
 * then it checks whether the allert is justified, by means of an xpath evaluation function.
 * 
 * @author Gabriela
 */

public class AlertService extends AbstractService
{
	public static Logger logger = Logger.getLogger(AlertService.class); 
	protected Properties serverConfig = new Properties();
	protected ArrayList<MailAlert> allerts = new ArrayList<MailAlert>();
	protected Properties props = new Properties();
	
	/**
	 * The method initializes the configuration: the logger attached to the web service, the configuration
	 * for the mail server (the proxy smtp server used to send allerts) and the configuration
	 * for the allerts (firing conditions).  
	 */
	
	public void init()
	{
		// initialize logger, then the configurations for the mail server and the allert configuration
	
		try
		{
			Utils instanceUtils = Utils.get();
			URL url = instanceUtils.getFile("configuration//" + Utils.LOGGER_FILE);
			if (url == null)
				System.out.println("---------------------URL NULL for logger" );
			else
			{	
				PropertyConfigurator.configure(url);
				System.out.println("Logger properties loaded ...");
			}
			
			// initialize the allert configuration
			props = instanceUtils.getResource(Utils.ALERT_CONFIG);			
			System.out.println("Check for allert: initialization of allerts done ...");
			
			// initialize the mail server configuration
			serverConfig = instanceUtils.getResource(Utils.MAILSERVER_SETTINGS);	
			System.out.println("Check for allert: initialization of mail server settings done..." );
		}
		catch(IOException e)
		{
			logger.warn("IOException occured...");
			e.printStackTrace();
		}
		catch(Exception ex)
		{
			logger.warn("Exception occured ..." + ex.getMessage());
			ex.printStackTrace();
		}
		
		// load the allerts parsed from the configuration file
		System.out.println("Loading the DATA from the config file ...");
		
		int count = Integer.parseInt(props.getProperty("alert.count").trim());
		System.out.println("nr alerte = " + count);
		for (int i=0; i < count; i++) {	
				System.out.println("val="+props.getProperty("alert"+i+".xpath").trim());
			MailAlert ma = new MailAlert(
					props.getProperty("alert"+i+".xpath").trim(), 
					props.getProperty("alert"+i+".from"),
					props.getProperty("alert"+i+".to"),
					props.getProperty("alert"+i+".subject"),
					props.getProperty("alert"+i+".body"));
			allerts.add(ma);
			System.out.println("Preparing email ..." + ma.getBody());
		}
	}
	
	/**
	 * No Annotations are added to the message, so the body of this function is void.
	 */
	public SAMLAnnotation generateAnnotation(String actor, String namespace, HashMap<String,Vector<String>> attributeNamesToValues, String target) throws SAMLException
	{ 
		return null;
	}
	
	/**
	 * A simple constructor that calls the init()
	 */
	public AlertService()
	{
		init();
	}
	
	/**
	 * Main method that is supposed to be public through the "serve" method; all functionality available here
	 */
	public org.apache.axis.Message invoke(org.apache.axis.Message req, org.apache.axis.Message resp) throws Exception {		
		// checking the allert conditions against the request message
		// if the allert condition is satisfied, the mail is sent with the desired configuration
		for (int i=0; i<allerts.size(); i++) {
			if (allerts.get(i).fireAlert(req.getSOAPEnvelope())) {
				System.out.println("One allert fired ...");
				sendMail(allerts.get(i),req.getSOAPEnvelope());
			}
		}
		return req;
	}
	
	/**
	 * Method for loading the properties needed for a custom configuration of the mail alerting service.
	 * @param propertyFile
	 * @return a Properties object
	 * @throws FileNotFoundException
	 * @throws InvalidPropertiesFormatException
	 * @throws IOException
	 */
	protected Properties loadProperties(String propertyFile) 
	throws FileNotFoundException, InvalidPropertiesFormatException,IOException 
	{	
		Properties defaultProps = new Properties();
		try
		{
			defaultProps = new Properties();
			System.out.println("----------------loading file " + propertyFile);
			FileInputStream in = new FileInputStream(propertyFile);
			
			defaultProps.load(in);
			in.close();
		}
		catch(Exception e)
		{
			logger.warn("CheckForAlertService: exception while loading properties");
			e.printStackTrace();
		}
		
		return defaultProps;
	
	}    
	
	/**
	 * This method that uses javax.mail to send an email.
	 * It sends the soap body modified over the specific format (loaded from the config files)
	 * @param ma  - the MailAlert instance carrying its own logic
	 * @param msg - the SOAPEnvelope that is used
	 * @throws Exception
	 */
	public void sendMail(MailAlert ma, SOAPEnvelope msg) throws Exception {
		logger.info("Alert fired: " + ma);
		
	    // Attaching to default Session, or we could start a new one 		    
	    Session session = Session.getDefaultInstance(serverConfig, null);
	    // Create a new message 
	    Message emsg = new MimeMessage(session);

	    emsg.setFrom(new InternetAddress(ma.getFrom()));
	    emsg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(ma.getTo(), false));

	    // Set the subject and body text 
	    String subj = ma.getSubject();
	    subj = subj.replaceAll("%m", msg.getBody().toString());	    
	    emsg.setSubject(subj);
	    
	    String body = ma.getBody();
	    body = body.replaceAll("%m", msg.getBody().toString());
	    emsg.setText(body);
	    
	    // Set some other header information 
	    emsg.setHeader("MyMailer", "MailAlertService");
	    emsg.setSentDate(new Date());
	    
	    // Send the message     
	    Transport.send(emsg);
	    logger.info("Message sent OK.");
	}
	
	 public static void fetchConfig(Properties serverConfig) 
	 {
	    InputStream input = null;
	    
	    System.out.println("Fetching mail server config...");
	    try {
	      input = new FileInputStream("configuration//" + Utils.MAILSERVER_SETTINGS);
	      serverConfig.load( input );
	    }
	    catch ( IOException ex ){
	      System.err.println("Cannot open and load mail server properties file.");
	    }
	    finally {
	      try {
	        if ( input != null ) input.close();
	      }
	      catch ( IOException ex ){
	        System.err.println( "Cannot close mail server properties file." );
	      }
	    }
	    
	    System.out.println("Fetched mail server config...!");
	  }
}
